#include "timeSync.h"
#include <stdio.h>
#include <math.h>

// #include "stm32h7xx_ll_utils.h"

 utc_t  utc  = {0};
 unix_t unix = {0}, unix1 = {0};
 gpst_t gpst = {0};

struct tSync_s t =
{
	.unix_s = 0,
	.unix_us = 0,
	.syst_ms = 0,
	.syst_us = 0,
	.unix_err_cnt = 0,
	.trigger_1pps_cnt = 0,
	.cur_1pps_syst_us = 0,
	.last_1pps_syst_us = 0,
	
	.calc_syst_us = tSync_calc_syst_us,
	.calc_unix_s  = tSync_calc_unix_s,
	.calib_unix_s = tSync_calib_unix_s,
	.get_syst_ms  = tSync_get_syst_ms,
	.get_syst_us  = tSync_get_syst_us,
	.get_unix_us  = tSync_get_unix_us,
	.get_tk_us    = tSync_get_tk_us
};

/* 需要调用底层寄存器，计算微秒级时间 应该从自动重装载值递减 */
void tSync_calc_syst_us(struct tSync_s* t)
{
	// t->syst_us = t->syst_ms * 1000 + (SysTick->LOAD - SysTick->VAL) * 0.0025641025641026;
}

/* 被1pps的外部中断调用 */
void tSync_calc_unix_s(struct tSync_s* t)
{
	t->calc_syst_us(t);
	t->trigger_1pps_cnt++;

	if (t->unix_s != 0)  // 已初始化
	{
		t->cur_1pps_syst_us = t->syst_us;
		double dt = (t->cur_1pps_syst_us - t->last_1pps_syst_us) * 1e-6;
		t->last_1pps_syst_us = t->cur_1pps_syst_us;
		t->unix_s += (uint32_t)(dt + 0.5);		// 四舍五入
	}
	else
	{
		t->unix_s = 0;
		t->last_1pps_syst_us = t->syst_us;
		t->cur_1pps_syst_us = t->last_1pps_syst_us;
	}
}

/* unix_s 是根据1PPS推算的，可能会有误差；如果接收到GNSS数据，则解析出包内的UNIX时间，进行对比判断 */
void tSync_calib_unix_s(struct tSync_s* t, int64_t unix_ref)
{
	if (t->trigger_1pps_cnt == 0) return;

	if (t->unix_s != 0)	// 已初始化
	{
		if (unix_ref != t->unix_s) // unix_s一定比unix_ref提前更新
		{
			t->unix_err_cnt++;
			/* to do reset unix....*/
		}
	}
	else // 进行初始化
	{
		t->unix_s = unix_ref;
		t->unix_us = t->unix_s * 1000000;
//		t->trigger_1pps_cnt = 1;
	}
}

uint64_t tSync_get_syst_ms(struct tSync_s* t)
{
	return (t->syst_ms);
}

/* 用来给传感器打时间戳 */
double tSync_get_unix_us (struct tSync_s* t)
{
	t->calc_syst_us(t);

	if (t->unix_s != 0)
	{
		t->unix_us = t->unix_s * 1000000 + (t->syst_us - t->cur_1pps_syst_us);
		return (t->unix_us);
	}
	else
	{
		return (t->syst_us);
	}	
}

double tSync_get_syst_us(struct tSync_s* t)
{
	t->calc_syst_us(t);
	return (t->syst_us);
}

double tSync_get_tk_us(struct tSync_s* t)
{
	return (tSync_get_unix_us(t));
}

void utc2unix(const utc_t *ep, unix_t *t)
{
	const int doy[] = {1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335};
	int days, sec, year = ep->year, mon = ep->month, day = ep->day;

	if (year < 1970 || 2099 < year || mon < 1 || 12 < mon)
	{
		t->sec = 0, t->time = 0;
	}

	/* leap year if year%4==0 in 1901-2099 */
	days = (year - 1970) * 365 + (year - 1969) / 4 + doy[mon - 1] + day - 2 + (year % 4 == 0 && mon >= 3 ? 1 : 0);
	// sec = (int)floor(ep->sec);	
	sec = (int)(ep->sec);
	t->time = (int64_t)days * 86400 + ep->hour * 3600 + ep->min * 60 + sec;
	t->sec = ep->sec - sec;
}

void unix2utc(const unix_t *t, utc_t *ep)
{
	const int mday[] = {/* # of days in a month */
						31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
						31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	int days, sec, mon, day;

	/* leap year if year%4==0 in 1901-2099 */
	days = (int)(t->time / 86400);
	sec = (int)(t->time - (int64_t)days * 86400);
	for (day = days % 1461, mon = 0; mon < 48; mon++)
	{
		if (day >= mday[mon])
			day -= mday[mon];
		else
			break;
	}
	ep->year  = (uint16_t)(1970 + days / 1461 * 4 + mon / 12);
	ep->month = (uint8_t)(mon % 12 + 1);
	ep->day   = (uint8_t)(day + 1);
	ep->hour  = (uint8_t)(sec / 3600);
	ep->min   = (uint8_t)(sec % 3600 / 60);
	ep->sec   = (double )(sec % 60 + t->sec);
}

/* utc + 18 = gpst*/
void gpst2unix(const gpst_t *gpst, unix_t *t, int leapSec)
{
	t->time = 315964800 + (int64_t)86400 * 7 * gpst->week - leapSec + (int)gpst->itow;
	t->sec = gpst->itow - (int)gpst->itow;
}

void unix2gpst(const unix_t *t, gpst_t *gpst, int leapSec)
{
	uint32_t spw = 86400 * 7;
	int64_t sec = t->time - 315964800 + leapSec;
	int w = (int)(sec / (spw));

	gpst->week = w;
	gpst->itow = (double)(sec - (double)w * spw) + t->sec;
}
